#ifndef RBT_HASH
#define RBT_HASH

#include "../typedef.h"

namespace Common
{
	class Hash
	{
	public:
		virtual uint32 GetHashValue(cwchar* source, cuint32 hashListLen) = 0;
		virtual uint32 GetHashValue(cchar* source, cuint32 hashListLen) = 0;

		virtual uint32 operator()(cwchar* source, cuint32 hashListLen) = 0;
		virtual uint32 operator()(cchar* source, cuint32 hashListLen) = 0;
	};

	class DefaultHash : public Hash
	{
	public:
		virtual uint32 GetHashValue(cwchar* source, cuint32 hashListLen)
		{
			register uint32 hashValue = 0;

			while (*source)
			{
				hashValue = (hashValue << 5) + hashValue + *source++;
			}

			return hashValue % hashListLen;
		}

		virtual uint32 GetHashValue(cchar* source, cuint32 hashListLen)
		{
			register uint32 hashValue = 0;

			while (*source)
			{
				hashValue = (hashValue << 5) + hashValue + *source++;
			}

			return hashValue % hashListLen;
		}

		virtual uint32 operator()(cwchar* source, cuint32 hashListLen)
		{
			return GetHashValue(source, hashListLen);
		}

		virtual uint32 operator()(cchar* source, cuint32 hashListLen)
		{
			return GetHashValue(source, hashListLen);
		}

		DefaultHash(){};
		virtual ~DefaultHash(){};
	};

	// T is the value specified by the Key, Key is used to compare when there are different T with the same Hash value
	template<class T, class Key>
	class HashList
	{
	public:

		int32 Add(cuint32 hashIndex, const T& value, const Key& key)
		{
			if (hashIndex > m_vecItem.size() - 1)
			{
				return R_FAILED;
			}

			m_vecItem[hashIndex].push_back(std::pair<Key, T>(key, value));

			return R_SUCCEED;
		}

		int32 Delete(cuint32 hashIndex, const T& value, const Key& key)
		{
			if (hashIndex > m_vecItem.size() - 1)
			{
				return R_FAILED;
			}

			std::vector<std::pair<Key, T> >& hashItemVec = m_vecItem[hashIndex];

			std::vector<std::pair<Key, T> >::iterator iterVec = hashItemVec.begin();
			while (iterVec != hashItemVec.end())
			{
				if (iterVec->first == key)
				{
					hashItemVec.erase(iterVec);
					break;
				}
				++iterVec;
			}

			return R_SUCCEED;
		}

		int32 Set(cuint32 hashIndex, const T& value, const Key& key)
		{
			if (hashIndex > m_vecItem.size() - 1)
			{
				return R_FAILED;
			}

			std::vector<std::pair<Key, T> >& hashItemVec = m_vecItem[hashIndex];

			std::vector<std::pair<Key, T> >::iterator iterVec = hashItemVec.begin();
			while (iterVec != hashItemVec.end())
			{
				if (iterVec->first == key)
				{
					iterVec->second = value;
					break;
				}
				++iterVec;
			}

			return R_SUCCEED;
		}

		int32 Get(cuint32 hashIndex, T& value, const Key& key)
		{
			if (hashIndex > m_vecItem.size() - 1)
			{
				return R_FAILED;
			}

			std::vector<std::pair<Key, T> >& hashItemVec = m_vecItem[hashIndex];

			std::vector<std::pair<Key, T> >::iterator iterVec = hashItemVec.begin();
			while (iterVec != hashItemVec.end())
			{
				if (iterVec->first == key)
				{
					value = iterVec->second;
					break;
				}
				++iterVec;
			}

			return R_SUCCEED;
		}

		HashList(uint32 hashListCapacity):m_vecItem(hashListCapacity, std::vector<std::pair<Key, T> >())
		{

		}

		~HashList(){};

	protected:
		HashList(){};

		std::vector<std::vector<std::pair<Key, T> > > m_vecItem;
	};
}

#endif